<script lang="ts" setup>
/**
 * Props
 * @defaultFile {String | Array<string>>} 默认文件路径
 *
 * @width {String} 宽度
 *
 * @height {String} 高度
 *
 * @multiple {Boolean} 是否多选
 * 默认 false
 *
 * @limitCount {String} 上传数量
 * 默认 10
 *
 * @limitSize {String} 上传大小
 * 默认 5MB (单位MB)
 *
 * @fileStyle {Object} 已上传图片样式
 *
 * @hiddenRemove {Boolean} 隐藏删除按钮
 * 默认 false
 *
 * @update {Boolean} 是否点击更换当前图片
 * 默认 false
 *
 * @disabled {Boolean} 是否禁用
 * 默认 false
 *
 * Emits
 * @file 返回当前已上传文件地址
 *
 * @uploading 是否正在上传图片中
 *
 * Slot 自定义上传按钮
 */
import { computed, PropType, ref, watch } from 'vue'
import Icon from '@C/Icon.vue'
import { Msg, MsgLoadingClear } from '@C/Msg'
import { autoBG, hasUnit, postFileReq } from '@U/common'
import getDate from '@U/getDate'
import { getWeiXinPrivacyAuthorization } from '@U/Auth'
import Popup from '@C/Popup.vue'
import Image from '@C/Image.vue'
import { hasVarArray, IObjArray } from '@/interface'
import type { IObj } from '@/interface'

const props = defineProps({
  defaultFile: {
    type: String as PropType<string | Array<string>>,
    required: false,
    default: '',
  },
  height: {
    type: String,
    required: false,
    default: '',
  },
  width: {
    type: String,
    required: false,
    default: '',
  },
  disabled: {
    type: Boolean,
    required: false,
    default: false,
  },
  multiple: {
    type: Boolean,
    required: false,
    default: false,
  },
  hiddenRemove: {
    type: Boolean,
    required: false,
    default: false,
  },
  update: {
    type: Boolean,
    required: false,
    default: false,
  },
  limitCount: {
    type: String,
    required: false,
    default: '10',
  },
  limitSize: {
    type: String,
    required: false,
    default: '5',
  },
  fileStyle: {
    type: Object,
    required: false,
    default: () => ({}),
  },
  uploaderPath: {
    type: String,
    required: false,
    default: '/api/file/upload',
  },
  previewImage: {
    type: String,
    required: false,
    default: '',
  },
})
const emits = defineEmits(['file', 'uploading'])

// 正在上传
const fileUploadCount = ref(0)
// 上传
const upload = () => {
  if (props.disabled) return
  if (file.value.length >= 3) return
  // 获取微信授权
  getWeiXinPrivacyAuthorization(() => {
    uni.chooseImage({
      count: props.multiple ? (updateCan.value ? 1 : +props.limitCount - file.value.length) : 1,
      sizeType: ['compressed'],
      success(res) {
        const { tempFilePaths } = res;
        (tempFilePaths as Array<string>).forEach((path) => {
          uni.getFileInfo({
            filePath: path,
            success: async (info) => {
              // 图片超出规定大小，压缩后直接上传
              if (info.size >= +props.limitSize * 1024 * 1024) {
                wx.compressImage({
                  src: path,
                  quality: 80,
                  success: (res: object) => {
                    uni.getFileInfo({
                      filePath: res.tempFilePath,
                      success: async () => {
                        fileUploadCount.value += 1
                        const fileItem = {
                          path,
                          _path: '',
                          created: getDate({ select: ['time'] }).time,
                          state: 1, // 1正在上传 2上传成功 3上传失败
                        }
                        emits('uploading', true)
                        if (props.multiple) {
                          if (updateCan.value) {
                            (file.value as Array<IObj>)[updateIndex.value as number] = fileItem
                            updateCan.value = false
                          } else {
                            file.value.push(fileItem)
                          }
                        } else {
                          file.value = fileItem
                        }
                        await postFileReq(props.uploaderPath, path)
                            .then(res => {
                              fileUploadCount.value -= 1
                              const { statusCode, data } = res
                              const nowData = JSON.parse(data)
                              const newFile: IObj = {
                                path: `${import.meta.env.VITE_SHOUDAO_IMG_URL }/${ nowData.data[0]}`,
                                _path: nowData.data[0],
                              }
                              if (statusCode === 200 && nowData.code === 200) {
                                newFile.state = 2
                              } else {
                                newFile.state = 3
                              }
                              if (props.multiple) {
                                if (updateCan.value) {
                                  (file.value as IObjArray)[updateIndex.value as number] = newFile
                                  updateCan.value = false
                                } else {
                                  (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                                }
                              } else {
                                file.value = newFile
                              }
                            })
                            .catch(err => {
                              fileUploadCount.value -= 1
                              console.log(err)
                              const newFile = {
                                state: 3,
                                path,
                              }
                              if (props.multiple) {
                                if (updateCan.value) {
                                  (file.value as IObjArray)[updateIndex.value as number] = newFile
                                } else {
                                  (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                                }
                              } else {
                                file.value = newFile
                              }
                            })
                      },
                    })
                  },
                })
                // return uni.showToast({ icon: 'error', title: `图片最大${props.limitSize}MB` })
              } else {
                fileUploadCount.value += 1
                const fileItem = {
                  path,
                  _path: '',
                  created: getDate({ select: ['time'] }).time,
                  state: 1, // 1正在上传 2上传成功 3上传失败
                }
                emits('uploading', true)
                if (props.multiple) {
                  if (updateCan.value) {
                    (file.value as Array<IObj>)[updateIndex.value as number] = fileItem
                    updateCan.value = false
                  } else {
                    file.value.push(fileItem)
                  }
                } else {
                  file.value = fileItem
                }
                await postFileReq(props.uploaderPath, path)
                    .then(res => {
                      fileUploadCount.value -= 1
                      const { statusCode, data } = res
                      const nowData = JSON.parse(data)
                      const newFile: IObj = {
                        path: `${import.meta.env.VITE_SHOUDAO_IMG_URL }/${ nowData.data[0]}`,
                        _path: nowData.data[0],
                      }
                      if (statusCode === 200 && nowData.code === 200) {
                        newFile.state = 2
                      } else {
                        newFile.state = 3
                      }
                      if (props.multiple) {
                        if (updateCan.value) {
                          (file.value as IObjArray)[updateIndex.value as number] = newFile
                          updateCan.value = false
                        } else {
                          (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                        }
                      } else {
                        file.value = newFile
                      }
                    })
                    .catch(err => {
                      fileUploadCount.value -= 1
                      console.log(err)
                      const newFile = {
                        state: 3,
                        path,
                      }
                      if (props.multiple) {
                        if (updateCan.value) {
                          (file.value as IObjArray)[updateIndex.value as number] = newFile
                        } else {
                          (file.value as IObjArray)[file.value.map((i: IObj) => i.created).indexOf(fileItem.created)] = newFile
                        }
                      } else {
                        file.value = newFile
                      }
                    })
              }
            },
          })
        })
      },
      fail(err) {
        console.log(err)
      },
    })
  })
}

// 更换图片
const updateCan = ref(false)
const updateIndex = ref(<number | null>null)

// 显示预览图片弹框
const isPreviewImage = ref()

const updateImage = (index?: number) => {
  if (!props.previewImage.length) {
    if (!props.update || props.disabled) return
    updateCan.value = true
    updateIndex.value = index as number
    upload()
  } else {
    isPreviewImage.value?.change()
  }
}

// 删除
const remove = (index?: number) => {
  if (typeof index === 'number') {
    (file.value as IObj)[index as number] = null
    file.value = file.value.filter((i: IObj | null) => i !== null)
  } else {
    file.value = {}
  }
}

// 当前已上传文件
const file = ref(<IObj | Array<IObj | null>>(props.multiple ? [] : {}))
setTimeout(() => {
  if (props.defaultFile !== '' && props.defaultFile?.length > 0) {
    if (hasVarArray(props.defaultFile)) {
      file.value = (props.defaultFile as Array<string>).map((path: string) => ({
        path: /^http/.test(path) ? path : `${import.meta.env.VITE_SHOUDAO_IMG_URL}/${path}`,
        _path: path,
        created: getDate({ select: ['time'] }).time,
        state: 2, // 1正在上传 2上传成功 3上传失败
      }))
      MsgLoadingClear()
    } else {
      file.value = {
        path: /^http/.test(props.defaultFile as string) ? props.defaultFile : `${import.meta.env.VITE_SHOUDAO_IMG_URL}/${props.defaultFile}`,
        _path: props.defaultFile,
        created: getDate({ select: ['time'] }).time,
        state: 2, // 1正在上传 2上传成功 3上传失败
      }
    }
  }
}, 3000)

watch(
    () => JSON.stringify(file.value),
    () => {
      const f = hasVarArray(file.value) ? file.value.map((i: IObj) => i._path) : (file.value as IObj)._path
      emits('file', f)
      if (fileUploadCount.value === 0) emits('uploading', false)
    },
)

</script>

<template>
  <div :style="{...(height ? {height: hasUnit(height)} : {}), ...(width ? {width: hasUnit(width)} : {})}" class="prm-upload">
    <div @tap="upload">
      <slot />
    </div>
    <template v-if="hasVarArray(file)">
      <div
        v-for="(d, i) in file"
        :key="d.path"
        :style="{background: d.state === 2 ? autoBG(d.path) : autoBG('https://shoudaostatic.oss-cn-shanghai.aliyuncs.com/MEIDAO-ZHIKE/upload_failed.png')}"
        class="prm-upload-file"
        @tap="updateImage(i)"
      >
        <div v-if="d.state !== 2" class="prm-upload-file-state">{{ d.state === 1 ? '正在上传' : d.state === 3 ? '上传失败' : '' }}</div>
        <div v-if="d.state === 2 && !hiddenRemove && !disabled" class="prm-upload-file-delete" @tap.stop="remove(i)">
          <Image name="delete_img" oss size="36rpx" type="png" />
        </div>
      </div>
    </template>
    <Popup ref="isPreviewImage" mask>
      <Image :name="props?.previewImage" height="600" style="margin: auto" type="png" width="600" />
    </Popup>
  </div>
</template>

<style lang="less" scoped>
.prm-upload {
  display: flex;
  flex-flow: wrap;
  position: relative;
  .prm-upload-file {
    width: 160rpx;
    height: 160rpx;
    position: relative;
    border-radius: 20rpx;
    overflow: hidden;
    border: 2rpx solid rgba(0, 0, 0, 0.15);
    margin: 0 24rpx 24rpx 0;
    .prm-upload-file-delete {
      position: absolute;
      top: -2rpx;
      right: -2rpx;
    }
    .prm-upload-file-state {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      right: 0;
      background: rgba(0, 0, 0, 0.45);
      font-size: 30rpx;
      color: white;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
  .prm-upload-btn {
    width: 180rpx;
    height: 180rpx;
    margin-bottom: 12px;
    background: white;
    border-radius: 20rpx;
    border: 0.5rpx dashed rgba(0, 0, 0, 0.15);
    transition: all .3s;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
    &:active {
      border-color: #ff8002;
    }
  }
}
</style>
